#include "datamediasafety.h"
#include "unistd.h"
#include "datamediavalidator.h"

#include <QElapsedTimer>
#include <QFileInfo>
#include <QFile>
#include <QDir>
#include <QDebug>

DataMediaSafety::DataMediaSafety(QObject *parent)
    : QObject(parent)
{

}

bool DataMediaSafety::load(const QString fileName, QByteArray data)
{
    Q_UNUSED(fileName)
    Q_UNUSED(data)
    return true;
}

bool DataMediaSafety::save(const QString fileName,  QByteArray data)
{
    QElapsedTimer t;
    t.start();

    QFileInfo fileInfo(fileName);
    // 如果目录不存在，则尝试创建目录
    QDir dir(fileInfo.absolutePath());
    if (!dir.exists() && !dir.mkpath(dir.absolutePath()))
    {
        qWarning() << QString("Save file %1 failed. Because can't mkpath %2.")
                      .arg(fileName)
                      .arg(dir.absolutePath());
        return false;
    }

    QString absFileName = fileInfo.absoluteFilePath();
    QString tmpFileName = QString("/tmp/") + fileInfo.fileName();
    if (QFile::exists(tmpFileName))
        QFile::remove(tmpFileName);

    // 先写到/tmp文件系统
    QFile file(tmpFileName);
    if (!file.open(QIODevice::WriteOnly))
    {
        qWarning() << "Couldn't open the file, " << tmpFileName;
        return false;
    }
    file.write(data);
    file.close();

    // 在文件最后添加校验码
    DataMediaValidator::appendVerifyCode(tmpFileName);

    // 复制到目标位置
    bool ret = false;
    if (copy(tmpFileName, absFileName))
    {
        QString fnBak = fileInfo.absolutePath() + "/." + fileInfo.fileName();
        // 复制多一份备份
        ret = copy(tmpFileName, fnBak);
    }

    qDebug() << QString("save file %1 cost %2 ms.").arg(fileName).arg(t.elapsed());

    return ret;
}

bool DataMediaSafety::copy(const QString &from, const QString &to)
{
    QFileInfo fileInfo(to);
    QString tmpFileName = fileInfo.fileName();
    if (QFile::exists(tmpFileName))
        QFile::remove(tmpFileName);

    QFile file1(from);
    file1.open(QIODevice::ReadOnly);
    if (!file1.isOpen())
        return false;

    QFile file2(to);
    file2.open(QIODevice::WriteOnly);
    if (!file2.isOpen())
        return false;

    file2.write(file1.readAll());
    file2.flush();

#ifdef Q_OS_LINUX
    // must have this code.
    ::fsync(file2.handle());
#endif

    file1.close();
    file2.close();

    return true;
}
